﻿using System;
using System.ServiceModel;
using System.Windows.Forms;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Client;
using System.ServiceModel.Description;
using System.Xml.Serialization;
using System.IO;
using Com.Enterprisecoding.TFS.CheckInNotifier.EventData;
using ibuddylib;

namespace Com.Enterprisecoding.TFS.CheckInNotifier {
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    internal partial class MainForm : Form, INotificationService {
        #region Data Members
        private Uri baseAddress;
        private Uri tfsServerUri;
        private const int servicePort = 8081;
        private ServiceHost service;
        private int subscriptionId;
        private IEventService eventService;
        private bool isServiceStarted = false;  
        private int totalCheckInCount;

        #region iBuddy stuff
        private BuddyDancePattern dance;
        private BuddyAnimator animator;
        private IBuddy iBuddy;
        private int tickCount = 0;
        #endregion
        #endregion

        #region Properties
        private int TotalCheckInCount {
            set {
                totalCheckInCount = value;

                totalCheckInEvents.Text = value.ToString();
                notifyIcon.BalloonTipText = isServiceStarted ? string.Format("{0} notification so far...", value) : "Check-Ins are not listening";
            }
            get { return totalCheckInCount; }
        }
        #endregion

        public MainForm() {
            InitializeComponent();

            baseAddress = new UriBuilder("http", System.Environment.MachineName, servicePort).Uri;

            TotalCheckInCount = 0;

            iBuddy = BuddyManager.Global.AnyBuddy;
            animator = new BuddyAnimator(iBuddy);
        }

        private void Subscribe2NotificationEvent() {
            var teamProjectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(tfsServerUri, new UICredentialsProvider());
            teamProjectCollection.EnsureAuthenticated();

            eventService = (IEventService)teamProjectCollection.GetService(typeof(IEventService));

            var deliveryPreference = new DeliveryPreference {
                Address = baseAddress.AbsoluteUri + "NotificationService",
                Schedule = DeliverySchedule.Immediate,
                Type = DeliveryType.Soap
            };

            subscriptionId = eventService.SubscribeEvent("CheckinEvent", string.Empty, deliveryPreference);
        }

        private void InitializeService() {
            service = new ServiceHost(this, baseAddress);

            service.AddServiceEndpoint(typeof(INotificationService), new WSHttpBinding(SecurityMode.None), "NotificationService");
            service.Open();
        }

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e) {
            base.OnClosing(e);

           if(isServiceStarted){
               UnsubscribeEvent();
               CloseService();
           }
        }

        private void CloseService() {
            if (service != null && service.State == CommunicationState.Opened) {
                service.Close();
            }
        }

        private void UnsubscribeEvent() {
            if (eventService == null || subscriptionId == default(int)) { return; }

            eventService.UnsubscribeEvent(subscriptionId);
        }

        #region INotificationService Members

        public void Notify(string eventXml, string tfsIdentityXml) {
            TotalCheckInCount++;

            var serializer = new XmlSerializer(typeof(CheckinEvent));

            var checkinEvent = (CheckinEvent)serializer.Deserialize(new StringReader(eventXml));

            beatTimer.Enabled = false;
            dance = new BuddyDancePattern(4);
            beatTimer.Enabled = true;
            tick();

            var notificationForm = new NotificationDialog(checkinEvent);
            notificationForm.Show();
        }

        #endregion

        private void startStopListening_Click(object sender, EventArgs e) {
            if (isServiceStarted) {
                UnsubscribeEvent();
                CloseService();

                startStopListening.Image = Properties.Resources.Start_32;
                startStopListening.Text = "&Start Listening";

                TotalCheckInCount = 0;
                serverUri.Enabled = true;
                isServiceStarted = false;
            }
            else {
                tfsServerUri = new Uri(serverUri.Text);

                InitializeService();
                Subscribe2NotificationEvent();

                startStopListening.Image = Properties.Resources.Stop_Red_32;
                startStopListening.Text = "&Stop Listening";

                serverUri.Enabled = false;
                isServiceStarted = true;
            }
        }

        private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e) {
            Show();
            WindowState = FormWindowState.Normal;
        }

        private void MainForm_Resize(object sender, EventArgs e) {
            if (WindowState == FormWindowState.Minimized) {
                notifyIcon.Visible = true;
                Hide();
            }
            else if (WindowState == FormWindowState.Normal) {
                notifyIcon.Visible = false;
            }
        }

        private void serverUri_TextChanged(object sender, EventArgs e) {
            startStopListening.Enabled = Uri.IsWellFormedUriString(serverUri.Text, UriKind.Absolute);
        }

        private void tick() {
            dance.step(animator);
            if (dance.Exhausted) {
                dance = new BuddyDancePattern(1);
            }

            if (++tickCount==35) {
                beatTimer.Enabled = false;
                tickCount = 0;

                #region Reset iBuddy
                iBuddy.HeartLight = HeartLight.Off;
                iBuddy.WingPosition = WingPosition.High;
                iBuddy.HeadColor = HeadColor.Off; 
                #endregion
            }
        }

        private void beatTimer_Tick(object sender, EventArgs e) {
            tick();
        }
    }
}